package com.vhly.ddxdecompiler.dexreader.file;

import com.vhly.ddxdecompiler.dexreader.io.DexInputStream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Hashtable;

/**
 * Created by IntelliJ IDEA.
 * User: vhly
 * Date: 2009-10-14
 * Time: 17:18:07
 *
 * @author vhly[FR]
 */
public class DexFile {
    public Hashtable<String, Object> offsetCache;

    /**
     * word data不丰
     */
    private final MixedItemSection wordData;
    /**
     * type类型定义部分
     */
    private final MixedItemSection typeLists;
    private final MixedItemSection map;
    /**
     * 字符串部分
     */
    private final MixedItemSection stringData;
    /**
     * 字符串ID部分
     */
    private final StringIdsSection stringIds = new StringIdsSection(this);
    /**
     * 类型ID部分
     */
    private final TypeIdsSection typeIds = new TypeIdsSection(this);

    /**
     * Proto ID部分
     */
    private final ProtoIdsSection protoIds = new ProtoIdsSection(this);
    /**
     * 成员部分
     */
    private final FieldIdsSection fieldIds = new FieldIdsSection(this);
    /**
     * 方法部分
     */
    private final MethodIdsSection methodIds = new MethodIdsSection(this);
    /**
     * Class定义部分
     */
    private final ClassDefsSection classDefs = new ClassDefsSection(this);
    /**
     * Class数据部分
     */
    private final MixedItemSection classData;
    private final MixedItemSection byteData;
    /**
     * 头部分
     */
    private final HeaderSection header = new HeaderSection(this);
    private final Section sections[];
    /**
     * 文件长度
     */
    private int fileSize;
    private int dumpWidth;

    /**
     * 构造方法
     */
    public DexFile() { // 初始化元素
        offsetCache = new Hashtable<String, Object>();
        typeLists = new MixedItemSection(null, this, 4, MixedItemSection.SortType.NONE);
        wordData = new MixedItemSection("word_data", this, 4, MixedItemSection.SortType.TYPE);
        stringData = new MixedItemSection("string_data", this, 1, MixedItemSection.SortType.INSTANCE);
        classData = new MixedItemSection(null, this, 1, MixedItemSection.SortType.NONE);
        byteData = new MixedItemSection("byte_data", this, 1, MixedItemSection.SortType.TYPE);
        map = new MixedItemSection("map", this, 4, MixedItemSection.SortType.NONE);
        sections = (new Section[]{
                header, stringIds, typeIds, protoIds, fieldIds, methodIds, classDefs,
                wordData, typeLists, stringData,
                byteData, classData, map
        });
        fileSize = -1;
        dumpWidth = 79;
    }

    public void read(DexInputStream din) throws IOException {
        // 文件头读取
        header.read(din);

        // 文件主体读取
        stringIds.read(din);
        typeIds.read(din);
        protoIds.read(din);
        fieldIds.read(din);
        methodIds.read(din);
        classDefs.read(din);

        // 文件数据读取
        ByteArrayOutputStream bout = null;
        int b;
        int offset = din.getOffset();

        try {
            bout = new ByteArrayOutputStream();
            while (true) {
                b = din.read();
                if (b == -1) {
                    break;
                }
                bout.write(b);
            }
            byte[] buf = bout.toByteArray();
            reloc(buf, offset);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
//        wordData.read(din);
//        typeLists.read(din);
//        stringData.read(din);
//        byteData.read(din);
//        classData.read(din);
//        map.read(din);
    }

    private void reloc(byte[] buf, int offset) throws IOException {
        ByteArrayInputStream bin;
        bin = new ByteArrayInputStream(buf);
        stringIds.reloc(bin, offset);
        typeIds.reloc(bin, offset);
        protoIds.reloc(bin, offset);
        fieldIds.reloc(bin, offset);
        methodIds.reloc(bin, offset);
        classDefs.reloc(bin, offset);
        bin.close();
    }

    public void write(DataOutputStream dout) throws IOException {

    }

    public StringIdsSection getStringIds() {
        return stringIds;
    }

    public TypeIdsSection getTypeIds() {
        return typeIds;
    }

    public ProtoIdsSection getProtoIds() {
        return protoIds;
    }

    public FieldIdsSection getFieldIds() {
        return fieldIds;
    }

    public MethodIdsSection getMethodIds() {
        return methodIds;
    }

    public ClassDefsSection getClassDefs() {
        return classDefs;
    }
}
